package com.css.util;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.crypto.symmetric.SM4;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import org.apache.commons.lang3.StringUtils;

public class SM4Utils {
    private static final String SM4Key="cb98ct3d2596t81f";
     /**
     * sm4加密
     * @param mode sm4加密的模式 ECB,CBC
     * @param padding 加密填充方式
     * @param iv 偏移量，CBC模式下需要传入,否则系统随机生成iv每次加密结果都不一样 转成byte[] 大小16
     * @param content 加密内容
     * @return
     */
    public static String encode(Mode mode, Padding padding, String iv, String content) {
        try {
            //校验参数
            if(StringUtils.isBlank(content)) {
                return null;
            }
            SymmetricCrypto sm4 = new SM4(mode, padding, SM4Key.getBytes());
            String encryptHex = null;
            if(mode.equals(Mode.CBC)) {
                sm4 = new SM4(mode, padding, SM4Key.getBytes(),iv.getBytes());
            }
            // 在NoPadding模式下需要手动补齐分组16字节倍数
            if(padding.equals(Padding.NoPadding)) {
                byte[] data = padding(content);
                encryptHex = sm4.encryptHex(data);
            }
            else {
                encryptHex = sm4.encryptHex(content.getBytes());
            }
            return encryptHex;
        } catch (Exception e) {
            e.printStackTrace();
//            logger.error("MS4加密失败");
        }
        return null;
    }
    /**
     * sm4解密
     * @param mode sm4加密的模式 ECB,CBC
     * @param padding 加密填充方式
     * @param iv 偏移量，CBC模式下需要传入,否则系统随机生成iv每次加密结果都不一样 转成byte[] 大小16
     * @param encodeContent 需解密字符串
     * @return
     */
    public static String decode(Mode mode, Padding padding ,String iv,String encodeContent) {
        try {
            //校验参数
            if(StringUtils.isBlank(encodeContent)) {
                return null;
            }
            SymmetricCrypto sm4 = new SM4(mode, padding, SM4Key.getBytes());
            if(mode.equals(Mode.CBC)) {
                sm4 = new SM4(mode, padding, SM4Key.getBytes(),iv.getBytes());
            }
            String decryptStr = sm4.decryptStr(encodeContent, CharsetUtil.CHARSET_UTF_8);
            return decryptStr;
        } catch (Exception e) {
            e.printStackTrace();
//            logger.error("SM4解密失败");
        }
        return null;
    }

    // 在NoPadding模式下需要手动对齐16字节的倍数
    public static byte[] padding(String arg_text) {
        byte[] encrypt = arg_text.getBytes();

        if (encrypt.length % 16 != 0) {
            byte[] padded = new byte[encrypt.length + 16 - (encrypt.length % 16)];
            System.arraycopy(encrypt, 0, padded, 0, encrypt.length);
            encrypt = padded;
        }
        return encrypt;
    }
    
    /**
     * sm4加密encryptBase64格式
     * @param mode sm4加密的模式 ECB,CBC
     * @param padding 加密填充方式
     * @param iv 偏移量，CBC模式下需要传入,否则系统随机生成iv每次加密结果都不一样 转成byte[] 大小16
     * @param content 加密内容
     * @return
     */
    public static String encodeBase64(Mode mode, Padding padding, String iv, String content) {
        try {
            //校验参数
            if(StringUtils.isBlank(content)) {
                return null;
            }
            SymmetricCrypto sm4 = new SM4(mode, padding, SM4Key.getBytes());
            String encryptBase64 = null;
            if(mode.equals(Mode.CBC)) {
                sm4 = new SM4(mode, padding, SM4Key.getBytes(),iv.getBytes());
            }
            // 在NoPadding模式下需要手动补齐分组16字节倍数
            if(padding.equals(Padding.NoPadding)) {
                byte[] data = padding(content);
                encryptBase64 = sm4.encryptBase64(data);
            }
            else {
            	encryptBase64 = sm4.encryptBase64(content.getBytes());
            }
            return encryptBase64;
        } catch (Exception e) {
            e.printStackTrace();
//            logger.error("MS4加密失败");
        }
        return null;
    }

    public static void main(String[] args) {

        String str6= encode(Mode.ECB,Padding.PKCS5Padding, null,"Abcd1234");
        System.out.println("PKCS5Padding:"+str6+"\n");
        System.out.print("md5:"+ MD5.create().digestHex("Abcd1234"));

    }
}
